/*
 * Universidade Estadual de Campinas - UNICAMP
 * MC823 - Laboratório de Redes
 * Alunos:
 *         Daniel Camillo C. Farias  RA: 059878
 *         Vitor Hugo Mickus Rodrigues RA: 072627
 * Professor:
 *         Paulo Lício e Celio
 *
 * Server program for Network Labs. Simulate an ECHO program.
 *
 */

#include "server_echo.h"


int count_received = 0 , count_chars_received = 0;
int sockfd = 0;

void  ALARMhandler(int sig)
{
  fprintf(stderr, "Number of reads: %d\n", count_received);
  fprintf(stderr, "Number of chars: %d\n", count_chars_received);
  close(sockfd);
  exit(0);
}

/*
 * Main Function, start of the program.
 *      Input:
 *            int argc:  number of parameters passed in command line.
 *            char* argv[]: the parameters passed in command line.
 *      Output:
 *            int : status of the program.             
 */
int main(int argc, char* argv[]) 
{
  // Local Variables
  int pid = -1, status = 0;
  int numbytes;
  struct sockaddr_in my_addr;    /* my address information */
  struct sockaddr_in their_addr; /* connector's address information */
  char buf[MAXBUFLEN];
  socklen_t addrlen = 0;
  
  // Fills struct
  my_addr.sin_family = AF_INET;         /* host byte order */
  my_addr.sin_port = htons(MYPORT);     /* short, network byte order */
  my_addr.sin_addr.s_addr = INADDR_ANY; /* automatically fill with my IP */
  bzero(&(my_addr.sin_zero), 8);        /* zero the rest of the struct */

  while(1) {  
    if((pid = fork()) == -1) {
      perror("Failed to fork!");
      exit(1);
    }

    if(pid == 0) {
      // Main loop
      signal(SIGALRM, ALARMhandler); 
     
      //Create socket descriptor
      if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
	perror("socket");
	exit(1);
      }    

      // Bind
      if (bind(sockfd, (struct sockaddr *)&my_addr, sizeof(struct sockaddr)) == -1) {
	perror("bind");
	exit(1);
      }

      // Connect
      // Get IP      
      addrlen = sizeof(struct sockaddr_in);
      #ifdef CONNECT
      numbytes = recvfrom(sockfd, buf, MAXBUFLEN-1 , 0, (struct sockaddr *)&their_addr, &addrlen); 
      sendto(sockfd, buf, numbytes, 0, (struct sockaddr *)&their_addr, addrlen);

      printf("server: got connection from %s\n", inet_ntoa(their_addr.sin_addr));

      #endif

      _CONNECT(sockfd, (struct sockaddr *)&their_addr, sizeof(struct sockaddr_in))

      while(1) {
	addrlen = sizeof(struct sockaddr_in);
	if ((numbytes= _RECV_FROM_CLIENT(sockfd, buf, MAXBUFLEN-1, (struct sockaddr *)&their_addr, &addrlen)) == -1)
	{
	  perror("RECV");
	  exit(1);
	}
	else if (numbytes == 0)	  
	{
	  #ifdef CONNECT
      	  ALARMhandler(0);
	  #endif
	}
	
	alarm(ALARM_TIMEOUT);

        count_received++;
        count_chars_received += numbytes;
	
	//Print some information	
	buf[numbytes]='\0';
	printf("%s", buf);
  
	if ((numbytes=_SEND_TO_CLIENT(sockfd, buf, numbytes, (struct sockaddr *)&their_addr, addrlen)) == -1) {
	  perror("sendto");
	  exit(1);
	}
      }
    } else {
      // Wait for child process.     
      if ((pid = wait(&status)) == -1) {
	perror("wait error");
	exit(1);
	//UNIMPLEMENTED: SIGKILL CHILD ON ERROR
      }
    }
  }
}
